请打开 MySQL 客户端,先创建实验数据库并导入以下测试数据。复制下方代码,一键粘贴运行即可。
teaching_db,运行下面的代码会先删除旧库再重建。请确认不会影响你的其他数据。
-- ==============================
-- 第6章 多关系数据查询 实验数据
-- ==============================
DROP DATABASE IF EXISTS teaching_db;
CREATE DATABASE teaching_db DEFAULT CHARSET utf8mb4;
USE teaching_db;
-- 学生表 s
CREATE TABLE s (
sno CHAR(4) PRIMARY KEY,
sn VARCHAR(20),
sex CHAR(2),
age INT,
maj VARCHAR(30)
);
INSERT INTO s VALUES
('s1', '赵亦', '女', 20, '计算机'),
('s2', '钱尔', '男', 21, '信息管理'),
('s3', '孙珊', '女', 19, '计算机'),
('s4', '李思', '男', 22, '信息管理'),
('s5', '周武', '男', 20, '计算机'),
('s6', '王彤', '女', 19, '计算机');
-- 课程表 c
CREATE TABLE c (
cno CHAR(4) PRIMARY KEY,
cn VARCHAR(30),
ct INT
);
INSERT INTO c VALUES
('c1', '数据库', 64),
('c2', '数学', 72),
('c3', '操作系统', 56),
('c4', '程序设计基础', 48),
('c5', '数据结构', 60);
-- 教师表 t
CREATE TABLE t (
tno CHAR(4) PRIMARY KEY,
tn VARCHAR(20),
sex CHAR(2),
prof VARCHAR(20)
);
INSERT INTO t VALUES
('t1', '李力', '男', '教授'),
('t2', '王平', '女', '副教授'),
('t3', '刘伟', '男', '讲师'),
('t4', '张雪', '女', '助教'),
('t5', '陈波', '男', '讲师'),
('t6', '张刚', '男', '教授');
-- 授课表 tc
CREATE TABLE tc (
tno CHAR(4),
cno CHAR(4),
PRIMARY KEY (tno, cno)
);
INSERT INTO tc VALUES
('t1', 'c1'),
('t2', 'c2'),
('t3', 'c3'),
('t3', 'c5'),
('t4', 'c4'),
('t5', 'c1');
-- 选课表 sc
CREATE TABLE sc (
sno CHAR(4),
cno CHAR(4),
score DECIMAL(5,1),
PRIMARY KEY (sno, cno)
);
INSERT INTO sc VALUES
('s1', 'c1', 90),
('s1', 'c2', 85),
('s1', 'c3', 88),
('s2', 'c1', 72),
('s2', 'c2', 68),
('s3', 'c1', 95),
('s3', 'c3', 78),
('s4', 'c2', 82),
('s4', 'c4', 60),
('s5', 'c1', 76),
('s5', 'c4', 55);
-- 验证数据
SELECT '学生表' AS 表名, COUNT(*) AS 记录数 FROM s
UNION ALL
SELECT '课程表', COUNT(*) FROM c
UNION ALL
SELECT '教师表', COUNT(*) FROM t
UNION ALL
SELECT '授课表', COUNT(*) FROM tc
UNION ALL
SELECT '选课表', COUNT(*) FROM sc;
| 表名 | 记录数 |
|---|---|
| 学生表 | 6 |
| 课程表 | 5 |
| 教师表 | 6 |
| 授课表 | 6 |
| 选课表 | 11 |
了解表之间的关联关系,后续任务会用到。
查询学号为 's5' 的学生的选课信息,列出学号、姓名和课程号。
(提示:需要连接学生表 s 和选课表 sc)
SELECT 表1.字段, ... FROM 表1 INNER JOIN 表2 ON 表1.共同列 = 表2.共同列 WHERE 条件;
SELECT s.sno, sn, cno
FROM s INNER JOIN sc
ON s.sno = sc.sno
WHERE s.sno = 's5';
sno 在两张表中都有,必须用 s.sno 加表前缀区分。
查询所有授课教师的教师号、姓名和课程名,按教师号升序排列。
(提示:需要连接三张表——教师表 t、授课表 tc、课程表 c)
FROM t INNER JOIN tc INNER JOIN c ON t.tno = tc.tno AND tc.cno = c.cno
SELECT t.tno, tn, cn
FROM t INNER JOIN tc INNER JOIN c
ON t.tno = tc.tno AND tc.cno = c.cno
ORDER BY tno;
查询所有教师的教师号、姓名和授课课程名(没有授课的教师也要显示,课程名显示为 NULL)。按教师号升序排列。
(提示:使用 LEFT JOIN)
FROM t LEFT OUTER JOIN tc ON ... LEFT OUTER JOIN c ON ...SELECT t.tno, tn, cn
FROM t LEFT JOIN tc ON t.tno = tc.tno
LEFT JOIN c ON tc.cno = c.cno
ORDER BY tno;
查询选课人数在 3 人及以上的课程号、课程名和选课人数。
SELECT c.cno, cn, COUNT(sc.sno) AS 选课人数
FROM c INNER JOIN sc
ON c.cno = sc.cno
GROUP BY c.cno, cn
HAVING COUNT(sc.sno) >= 3;
关键:先 INNER JOIN 连接课程表和选课表 → GROUP BY 分组 → HAVING 过滤。注意 HAVING 中要重写 COUNT 表达式,不能直接用别名"选课人数"(MySQL 允许,但 SQL 标准不允许)。
查询所有学生的学号、姓名、课程号和成绩(没有选课的学生也要显示)。请分别用 LEFT JOIN 和 RIGHT JOIN 两种方式实现。
SELECT s.sno, sn, cno, score
FROM s LEFT JOIN sc
ON s.sno = sc.sno;
SELECT s.sno, sn, cno, score
FROM sc RIGHT JOIN s
ON s.sno = sc.sno;
交换两张表的位置后,LEFT 变 RIGHT,主表不变,结果相同。
使用自连接查询比"程序设计基础"课时高的课程号、课程名和课时。
SELECT x.cno AS 课程号, x.cn AS 课程名, x.ct AS 课时
FROM c AS x INNER JOIN c AS y
ON x.ct > y.ct AND y.cn = '程序设计基础';
y 锁定"程序设计基础"的课时(48),x 遍历所有课程找出课时 > 48 的行。
查询与学生"王彤"专业相同的所有学生的学号和姓名(结果中不包含王彤本人)。
思考:如何用自连接实现?如何排除本人?
SELECT x.sno, x.sn
FROM s AS x INNER JOIN s AS y
ON x.maj = y.maj
AND y.sn = '王彤'
AND x.sn != '王彤';
关键在最后一个条件 x.sn != '王彤',排除了本人。也可用 x.sno != y.sno 来排除。
查询每位学生的学号、姓名、选修课程名和成绩。没有选课的学生也要显示,课程名和成绩为 NULL。结果按学号升序排列。
(提示:需要三表连接 + 外连接)
SELECT s.sno, sn, cn, score
FROM s
LEFT JOIN sc ON s.sno = sc.sno
LEFT JOIN c ON sc.cno = c.cno
ORDER BY s.sno;
两个 LEFT JOIN 都以学生表 s 为主表,确保即使没选课的 s6 也能出现。如果第二个连接用 INNER JOIN,当 sc.cno 为 NULL 时,课程表不会匹配,s6 那行会被丢弃。
勾选你已完成的任务,追踪实验进度:
完成进度:0 / 9